home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 February / EnigmA AMIGA RUN 04 (1996)(G.R. Edizioni)(IT)[!][issue 1996-02][Skylink CD III].iso / earcd / util1 / screnkys.lha / ScreenKeys.c < prev    next >
C/C++ Source or Header  |  1995-12-17  |  11KB  |  645 lines

  1. /*
  2.  * ScreenKeys - A small and simple screen hotkey commodity.
  3.  *
  4.  * Public domain in 1995 by Magnus Holmgren.
  5.  *
  6.  * Written using the DICE compiler - no startup code.
  7.  *
  8.  * #define OS3 to get a somewhat smaller, OS 3.0+-specific version.
  9.  */
  10. #include <clib/alib_protos.h>
  11. #include <clib/commodities_protos.h>
  12. #include <clib/dos_protos.h>
  13. #include <clib/exec_protos.h>
  14. #include <clib/intuition_protos.h>
  15. #include <clib/icon_protos.h>
  16. #include <clib/utility_protos.h>
  17. #include <exec/alerts.h>
  18. #include <exec/execbase.h>
  19. #include <exec/memory.h>
  20. #include <intuition/intuitionbase.h>
  21. #include <workbench/startup.h>
  22. #include <string.h>
  23.  
  24.  
  25. #define VERSION    "1.2"
  26.  
  27.  
  28. /******************** Global variables ********************/
  29.  
  30.  
  31. struct DosLibrary    *DOSBase;
  32. struct Library        *CxBase;
  33. struct Library        *IconBase;
  34. struct IntuitionBase    *IntuitionBase;
  35. struct ExecBase        *SysBase;
  36. struct Library        *UtilityBase;
  37.  
  38. struct MsgPort        *CxPort;
  39. struct WBStartup    *WBMsg;
  40. CxObj            *Broker;
  41.  
  42. BOOL    DoToBack;
  43.  
  44.  
  45. /******************** Startup code ********************/
  46.  
  47.  
  48. #ifdef OS3
  49. #define MINVER 39
  50. #else
  51. #define MINVER 37
  52. #endif
  53.  
  54.  
  55. LONG    Main( VOID );
  56.  
  57.  
  58. __geta4 LONG
  59. Startup( VOID )
  60. {
  61.     LONG    r;
  62.  
  63.     SysBase = *( ( struct ExecBase ** ) 4 );
  64.  
  65.     {
  66.         struct Process    *thisTask = ( struct Process * ) FindTask( NULL );
  67.  
  68.         if( !thisTask->pr_CLI )
  69.         {
  70.             /* Handle Workbench startup message */
  71.             struct MsgPort    *port = &thisTask->pr_MsgPort;
  72.  
  73.             WaitPort( port );
  74.             WBMsg = ( struct WBStartup * ) GetMsg( port );
  75.         }
  76.     }
  77.  
  78.     SetSignal( 0, SIGBREAKF_CTRL_C );
  79.  
  80.     if( SysBase->LibNode.lib_Version >= MINVER )
  81.     {
  82.         r = Main();
  83.     }
  84.     else
  85.     {
  86.         r = 100;
  87.     }
  88.  
  89.     if( WBMsg )
  90.     {
  91.         Forbid();
  92.         ReplyMsg( ( struct Message * ) WBMsg );
  93.     }
  94.  
  95.     return( r );
  96. }
  97.  
  98.  
  99. /******************** String constants ********************/
  100.  
  101.  
  102. const TEXT Ver[]        = "ScreenKeys " VERSION " (" __COMMODORE_DATE__ ")";
  103.  
  104. /* No localization yet... Would be quite easy to add though */
  105. const TEXT MSG_ERRORTITLE[]    = "ScreenKeys error";
  106. const TEXT MSG_QUIT_GAD[]    = "Quit";
  107. const TEXT MSG_NO_MEM[]        = "Not enough memory!";
  108. const TEXT MSG_NO_LIB[]        = "Couldn't open %s\nversion %ld or higher!";
  109. const TEXT MSG_NO_PAT[]        = "Couldn't parse pattern\n\"%s\"!";
  110. const TEXT MSG_NO_SCR[]        = "No hotkeys specified!";
  111. const TEXT MSG_NO_ICON[]    = "Couldn't open program icon!";
  112. const TEXT MSG_NO_BROKER[]    = "Couldn't create broker!";
  113. const TEXT MSG_BAD_FILTER[]    = "Bad input description:\n\"%s\"!";
  114. const TEXT MSG_NO_CLI[]        = "Shell start not yet supported\n";
  115. const TEXT MSG_DESCRIPTION[]    = "Provides hotkeys for screens";
  116.  
  117.  
  118.  
  119. /******************** Pool support ********************/
  120.  
  121.  
  122. /* Note: For this to work with DICE, some assembler stubs are needed (basically
  123.  * "converting" the '@' prefix generated by DICE, to the '_' prefix in pools.lib.
  124.  * In the DMakeFile, this is handled by the miscsr.lib. Should be trivial to
  125.  * fix, if needed. Or you could change the prototypes to stack arguments, and use
  126.  * the Lib#? functions instead.
  127.  */
  128. APTR AsmCreatePool(  __D0 ULONG, __D1 ULONG, __D2 ULONG, __A6 struct ExecBase * );
  129. VOID AsmDeletePool(  __A0 APTR,  __A6 struct ExecBase * );
  130. APTR AsmAllocPooled( __A0 APTR,  __D0 ULONG, __A6 struct ExecBase * );
  131. APTR AsmFreePooled(  __A0 APTR,  __A1 APTR,  __D0 ULONG, __A6 struct ExecBase * );
  132.  
  133.  
  134. APTR MemoryPool;
  135.  
  136.  
  137. LONG
  138. InitPool( VOID )
  139. {
  140. #ifdef OS3
  141.     return( ( LONG ) ( MemoryPool = CreatePool( MEMF_CLEAR | MEMF_PUBLIC, 2048, 1024 ) ) );
  142. #else
  143.     return( ( LONG ) ( MemoryPool = AsmCreatePool( MEMF_CLEAR | MEMF_PUBLIC, 2048, 1024, SysBase ) ) );
  144. #endif
  145. }
  146.  
  147.  
  148. VOID
  149. FreePool( VOID )
  150. {
  151.     if( MemoryPool )
  152.     {
  153. #ifdef OS3
  154.         DeletePool( MemoryPool );
  155. #else
  156.         AsmDeletePool( MemoryPool, SysBase );
  157. #endif
  158.         MemoryPool = NULL;
  159.     }
  160. }
  161.  
  162.  
  163. APTR
  164. MemAlloc( ULONG size )
  165. {
  166.     APTR    *mem;
  167.  
  168.     size += 4;
  169.  
  170. #ifdef OS3
  171.     if( mem = AllocPooled( MemoryPool, size ) )
  172. #else
  173.     if( mem = AsmAllocPooled( MemoryPool, size, SysBase ) )
  174. #endif
  175.     {
  176.         *( ( ( ULONG * ) mem )++ ) = size;
  177.     }
  178.  
  179.     return( mem );
  180. }
  181.  
  182.  
  183. /* Not used at the moment */
  184. #ifdef MEM_FREE_NEEDED
  185. VOID
  186. MemFree( APTR mem )
  187. {
  188.     if( mem )
  189.     {
  190.         ULONG    size = *( --( ( ULONG * ) mem ) );
  191. #ifdef OS3
  192.         FreePooled( MemoryPool, mem, size );
  193. #else
  194.         AsmFreePooled( MemoryPool, mem, size, SysBase );
  195. #endif
  196.     }
  197. }
  198. #endif
  199.  
  200.  
  201. /******************** Misc ********************/
  202.  
  203.  
  204. LONG
  205. MyRequest( STRPTR title, STRPTR body, STRPTR gads, ... )
  206. {
  207.     struct EasyStruct    es;
  208.  
  209.     es.es_StructSize = sizeof( es );
  210.     es.es_Flags = 0;
  211.     es.es_Title = title;
  212.     es.es_TextFormat = body;
  213.     es.es_GadgetFormat = gads;
  214.     return( EasyRequestArgs( NULL, &es, NULL, &gads + 1 ) );
  215. }
  216.  
  217.  
  218. VOID
  219. ErrRequest( STRPTR body, ... )
  220. {
  221.     MyRequest( MSG_ERRORTITLE, body, MSG_QUIT_GAD, &body + 1 );
  222. }
  223.  
  224.  
  225. VOID
  226. MemError( VOID )
  227. {
  228.     ErrRequest( MSG_NO_MEM );
  229. }
  230.  
  231.  
  232. struct Library *
  233. OpenLib( STRPTR name, LONG ver )
  234. {
  235.     struct Library    *lib;
  236.  
  237.     if( !( lib = OpenLibrary( name, ver ) ) )
  238.     {
  239.         ErrRequest( MSG_NO_LIB, name, ver );
  240.     }
  241.  
  242.     return( lib );
  243. }
  244.  
  245.  
  246. /******************** Argument parsing ********************/
  247.  
  248.  
  249. /* Convert string to caseless pattern. Shows error requesters. */
  250. STRPTR
  251. MakePattern( STRPTR str )
  252. {
  253.     STRPTR    pat;
  254.     LONG    len = strlen( str ) * 2 + 2;
  255.  
  256.     if( pat = MemAlloc( len ) )
  257.     {
  258.         if( ParsePatternNoCase( str, pat, len ) < 0 )
  259.         {
  260.             ErrRequest( MSG_NO_PAT, str );
  261.             pat = NULL;
  262.         }
  263.     }
  264.     else
  265.     {
  266.         MemError();
  267.     }
  268.  
  269.     return( pat );
  270. }
  271.  
  272.  
  273. /* Make a hotkey for the specified screen. Screen will be used
  274.  * as the id (!), which makes the Commodity message loop very simple.
  275.  */
  276. CxObj *
  277. MakeHotKey( STRPTR hotkey, STRPTR screen )
  278. {
  279.     CxObj    *hot;
  280.  
  281.     if( hot = HotKey( hotkey, CxPort, ( LONG ) screen ) )
  282.     {
  283.         if( CxObjError( hot ) )
  284.         {
  285.             ErrRequest( MSG_BAD_FILTER, hotkey );
  286.             DeleteCxObj( hot );
  287.             hot = NULL;
  288.         }
  289.     }
  290.     else
  291.     {
  292.         MemError();
  293.     }
  294.  
  295.     return( hot );
  296. }
  297.  
  298.  
  299. /* Parse a SCREENKEY tooltype */
  300. BOOL
  301. ParseHotKey( CxObj *broker, STRPTR arg )
  302. {
  303.     struct CSource    in;
  304.     TEXT    buf[ 256 ];
  305.     LONG    i;
  306.     BOOL    ret = FALSE;
  307.  
  308.     in.CS_Buffer = arg;
  309.     in.CS_Length = strlen( arg );
  310.     in.CS_CurChr = 0;
  311.  
  312.     /* Maybe not used often, but it is quite handy.
  313.      * Similar to strtok, but with quote support.
  314.      */
  315.     i = ReadItem( buf, sizeof( buf ), &in );
  316.  
  317.     if( ( i == ITEM_UNQUOTED ) || ( i == ITEM_QUOTED ) )
  318.     {
  319.         STRPTR    screen;
  320.         LONG    i;
  321.  
  322. #ifndef OS3
  323.         /* Fix ParsePatternNoCase bug */
  324.         for( screen = buf; *screen; ++screen )
  325.         {
  326.             *screen = ToUpper( *screen );
  327.         }
  328. #endif
  329.  
  330.         screen = MakePattern( buf );
  331.  
  332.         while( ( i = ReadItem( buf, sizeof( buf ), &in ) ) == ITEM_EQUAL )
  333.         {
  334.         }
  335.  
  336.         if( screen && ( ( i == ITEM_UNQUOTED ) || ( i == ITEM_QUOTED ) ) )
  337.         {
  338.             CxObj    *hotkey;
  339.  
  340.             if( hotkey = MakeHotKey( buf, screen ) )
  341.             {
  342.                 AttachCxObj( broker, hotkey );
  343.                 ret = TRUE;
  344.             }
  345.         }
  346.     }
  347.  
  348.     return( ret );
  349. }
  350.  
  351.  
  352. /* Get the CX_PRIORITY value */
  353. LONG
  354. GetCxPri( struct DiskObject *icon )
  355. {
  356.     STRPTR    str;
  357.     LONG    val = 0;
  358.  
  359.     if( str = FindToolType( icon->do_ToolTypes, "CX_PRIORITY" ) )
  360.     {
  361.         StrToLong( str, &val );
  362.     }
  363.  
  364.     return( val );
  365. }
  366.  
  367.  
  368. /* Add hotkeys for the screens to the broker */
  369. BOOL
  370. AddHotKeys( CxObj *broker, struct DiskObject *icon )
  371. {
  372.     STRPTR    *args;
  373.     BOOL    err = FALSE, keys = FALSE;
  374.  
  375.     SetIoErr( 0 );
  376.  
  377.     for( args = icon->do_ToolTypes; *args; ++args )
  378.     {
  379.         if( !Strnicmp( "SCREENKEY=", *args, 10 ) )
  380.         {
  381.             if( !ParseHotKey( broker, *args + 10 ) )
  382.             {
  383.                 err = TRUE;
  384.                 break;
  385.             }
  386.             else
  387.             {
  388.                 keys = TRUE;
  389.             }
  390.         }
  391.     }
  392.  
  393.     if( !( err || keys ) )
  394.     {
  395.         ErrRequest( MSG_NO_SCR );
  396.         return( FALSE );
  397.     }
  398.     else
  399.     {
  400.         return( !err );
  401.     }
  402. }
  403.  
  404.  
  405. /******************** Commodity support ********************/
  406.  
  407.  
  408. struct NewBroker    NewBroker =
  409. {
  410.     NB_VERSION,
  411.     "ScreenKeys",
  412.     "ScreenKeys "VERSION,
  413.     MSG_DESCRIPTION,
  414.     NBU_UNIQUE, 0, 0,
  415.     NULL, 0
  416. };
  417.  
  418.  
  419. VOID
  420. FreeBroker( VOID )
  421. {
  422.     DeleteCxObjAll( Broker );
  423.     DeleteMsgPort( CxPort );
  424. }
  425.  
  426.  
  427. BOOL
  428. InitBroker( VOID )
  429. {
  430.     BOOL    ret = FALSE;
  431.  
  432.     if( IconBase = OpenLib( "icon.library", 37 ) )
  433.     {
  434.         struct DiskObject    *icon;
  435.         BPTR    oldDir;
  436.  
  437.         oldDir = CurrentDir( WBMsg->sm_ArgList[ 0 ].wa_Lock );
  438.  
  439.         if( icon = GetDiskObject( WBMsg->sm_ArgList[ 0 ].wa_Name ) )
  440.         {
  441.             NewBroker.nb_Pri = GetCxPri( icon );
  442.             DoToBack = ( BOOL ) FindToolType( icon->do_ToolTypes, "SCREENTOBACK" );
  443.  
  444.             if( CxPort = NewBroker.nb_Port = CreateMsgPort() )
  445.             {
  446.                 LONG    err;
  447.  
  448.                 if( Broker = CxBroker( &NewBroker, &err ) )
  449.                 {
  450.                     ret = AddHotKeys( Broker, icon );
  451.                 }
  452.                 else if( err != CBERR_DUP )
  453.                 {
  454.                     ErrRequest( MSG_NO_BROKER );
  455.                 }
  456.             }
  457.  
  458.             FreeDiskObject( icon );
  459.         }
  460.         else
  461.         {
  462.             ErrRequest( MSG_NO_ICON );
  463.         }
  464.  
  465.         CurrentDir( oldDir );
  466.         CloseLibrary( IconBase );
  467.     }
  468.  
  469.     if( !ret )
  470.     {
  471.         FreeBroker();
  472.     }
  473.  
  474.     return( ret );
  475. }
  476.  
  477.  
  478. VOID
  479. HandleHotKey( STRPTR screen )
  480. {
  481.     struct Screen    *scr, *front;
  482.     ULONG    lock = LockIBase( 0 );
  483.  
  484.     if( front = IntuitionBase->FirstScreen )
  485.     {
  486.         for( scr = front->NextScreen; scr; scr = scr->NextScreen )
  487.         {
  488.             if( scr->Title && MatchPatternNoCase( screen, scr->Title ) )
  489.             {
  490.                 /* So screen won't close "beneath" us */
  491.                 Forbid();
  492.                 UnlockIBase( lock );
  493.                 ScreenToFront( scr );
  494.  
  495.                 if( DoToBack )
  496.                 {
  497.                     /* So cycling works as intended */
  498.                     ScreenToBack( front );
  499.                 }
  500.  
  501.                 Permit();
  502.                 return;
  503.             }
  504.         }
  505.     }
  506.  
  507.     UnlockIBase( lock );
  508. }
  509.  
  510.  
  511. BOOL
  512. HandleCxPort( VOID )
  513. {
  514.     CxMsg    *msg;
  515.     BOOL    run = TRUE;
  516.  
  517.     while( msg = ( CxMsg * ) GetMsg( CxPort ) )
  518.     {
  519.         LONG    id, type;
  520.  
  521.         id = CxMsgID( msg );
  522.         type = CxMsgType( msg );
  523.         ReplyMsg( ( struct Message * ) msg );
  524.  
  525.         switch( type )
  526.         {
  527.             case CXM_IEVENT:
  528.                 HandleHotKey( ( STRPTR ) id );
  529.                 break;
  530.  
  531.             case CXM_COMMAND:
  532.                 switch( id )
  533.                 {
  534.                     case CXCMD_DISABLE:
  535.                         ActivateCxObj( Broker, FALSE );
  536.                         break;
  537.  
  538.                     case CXCMD_ENABLE:
  539.                         ActivateCxObj( Broker, TRUE );
  540.                         break;
  541.  
  542.                     case CXCMD_KILL:
  543.                         run = FALSE;
  544.                         break;
  545.                 }
  546.  
  547.                 break;
  548.         }
  549.     }
  550.  
  551.     return( run );
  552. }
  553.  
  554.  
  555. /******************** Main program ********************/
  556.  
  557.  
  558. VOID
  559. MainLoop( VOID )
  560. {
  561.     LONG    cxMask = 1 << CxPort->mp_SigBit;
  562.     BOOL    run = TRUE;
  563.  
  564.     ActivateCxObj( Broker, TRUE );
  565.  
  566.     while( run )
  567.     {
  568.         LONG    sigs;
  569.  
  570.         sigs = Wait( cxMask | SIGBREAKF_CTRL_C );
  571.  
  572.         if( sigs & cxMask )
  573.         {
  574.             if( !HandleCxPort() )
  575.             {
  576.                 run = FALSE;
  577.             }
  578.         }
  579.  
  580.         if( sigs & SIGBREAKF_CTRL_C )
  581.         {
  582.             run = FALSE;
  583.         }
  584.     }
  585. }
  586.  
  587.  
  588. LONG
  589. Main( VOID )
  590. {
  591.     LONG    ret = RETURN_FAIL;
  592.  
  593.     if( DOSBase = ( struct DosLibrary * ) OpenLibrary( "dos.library", 37 ) )
  594.     {
  595.         if( WBMsg )
  596.         {
  597.             if( IntuitionBase = ( struct IntuitionBase * ) OpenLibrary( "intuition.library", 37 ) )
  598.             {
  599.                 if( UtilityBase = OpenLib( "utility.library", 37 ) )
  600.                 {
  601.                     if( CxBase = OpenLib( "commodities.library", 37 ) )
  602.                     {
  603.                         if( InitPool() )
  604.                         {
  605.                             if( InitBroker() )
  606.                             {
  607.                                 MainLoop();
  608.                                 FreeBroker();
  609.                             }
  610.  
  611.                             FreePool();
  612.                         }
  613.                         else
  614.                         {
  615.                             MemError();
  616.                         }
  617.  
  618.                         CloseLibrary( CxBase );
  619.                     }
  620.  
  621.                     CloseLibrary( UtilityBase );
  622.                 }
  623.  
  624.                 CloseLibrary( ( struct Library * ) IntuitionBase );
  625.             }
  626.             else
  627.             {
  628.                 Alert( AT_Recovery | AN_Unknown | AG_OpenLib | AO_Intuition );
  629.             }
  630.         }
  631.         else
  632.         {
  633.             PutStr( MSG_NO_CLI );
  634.         }
  635.  
  636.         CloseLibrary( ( struct Library * ) DOSBase );
  637.     }
  638.     else
  639.     {
  640.         Alert( AT_Recovery | AN_Unknown | AG_OpenLib | AO_DOSLib );
  641.     }
  642.  
  643.     return( ret );
  644. }
  645.